﻿namespace Hotel.Module.Resources
{
    using System;
    using System.Collections.Generic;
    using System.Linq;
    using Hotel.Module.Infrastructure;
    using Hotel.Module.Resources.Models;

    public class HotelResourcesController : DomainControllerBase, IResourseManagment
    {
        #region Constructors

        public HotelResourcesController(IServiceProvider provider)
            : base(provider, null, false)
        {
            initializeRepository();
        }

        public HotelResourcesController(IServiceProvider provider, ITransaction transaction, bool autoCommit)
            : base(provider, transaction, autoCommit)
        {
            initializeRepository();
        }

        #endregion

        #region IRoomManagement members

        public List<Hall> GetHalls()
        {
            return Storage.Enumerate<Hall>().ToList();
        }

        public List<Room> GetAllRooms()
        {
            return Storage.Enumerate<Room>().ToList();
        }

        public List<Hall> GetFreeHalls(DateTime indate, DateTime outdate, HallType type)
        {
            List<Hall> Allhalls = GetHalls();
            List<Hall> FreeHalls = new List<Hall>();

            foreach (var item in Allhalls)
            {
                bool flag = true;
                foreach (var per in item.Periods)
                {
                    if (!(((per.InDate < indate && per.OutDate < indate) || (per.InDate > outdate && per.OutDate > outdate)) && item.Type == type))
                    {
                        flag = false;
                        break;
                    }
                }

                if (flag)
                {
                    FreeHalls.Add(item);
                }
            }
            return FreeHalls;
        }

        public List<Room> GetFreeRooms(DateTime indate, DateTime outdate, RoomType type)
        {
            List<Room> Allrooms = GetAllRooms();
            List<Room> FreeRooms = new List<Room>();

            foreach (var item in Allrooms)
            {
                bool flag = false;
                if (item.Type == type)
                { flag = true; }
                foreach (var per in item.Periods)
                {
                    if (!((per.InDate < indate && per.OutDate < indate) || (per.InDate > outdate && per.OutDate > outdate)))
                    {
                        flag = false;
                        break;
                    }
                }

                if (flag)
                {
                    FreeRooms.Add(item);
                }
            }
            return FreeRooms;
        }

        #endregion

        /// <summary>
        /// Save changes made in Repository
        /// </summary>
        public void SaveChanges()
        {
            Storage.SaveChanges();
        }

        /// <summary>
        /// Release rooms if order cancelled
        /// </summary>
        /// <param name="ID">Order ID</param>
        public void FreeRoomsByOrderID(int ID)
        {
            List<Room> rooms = GetAllRooms();
            List<Room> _roomsWithPeriodsToDelete = new List<Room>();
            List<Period> _periodsToDelete = new List<Period>();

            foreach (var room in rooms)
            {
                foreach (var period in room.Periods)
                {
                    if (period.OrderID == ID)
                    {
                        _roomsWithPeriodsToDelete.Add(room);
                        _periodsToDelete.Add(period);
                    }
                }
            }

            int i = 0;
            foreach (var room in _roomsWithPeriodsToDelete)
            {
                room.Periods.Remove(_periodsToDelete[i]);
                Storage.Update(room);
                i++;
            }
            SaveChanges();
        }

        /// <summary>
        /// Get total cost of provided services
        /// </summary>
        /// <param name="ServicesIDs">IDs of services</param>
        /// <returns>Total cost of provided services</returns>
        public double GetServicesTotalCost(List<int> ServicesIDs)
        {
            double totalCost = 0;

            foreach (int id in ServicesIDs)
            {
                Predicate<Service> match = m => m.ID == id;
                Service found = (Service)Storage.Find(match);
                totalCost += found.Cost;
            }

            return totalCost;
        }

        /// <summary>
        /// Get Service from Repository by ID
        /// </summary>
        /// <param name="ID">Service ID</param>
        /// <returns>Sought-for Service</returns>
        public Service GetServiceByID(int ID)
        {
            Predicate<Service> match = m => m.ID == ID;
            return (Service)Storage.Find(match);
        }

        /// <summary>
        /// Get Service from Repository by Name
        /// </summary>
        /// <param name="ServiceName">Service Name</param>
        /// <returns>Sought-for Service</returns>
        public Service GetServiceByName(string ServiceName)
        {
            Predicate<Service> match = m => m.Name == ServiceName;
            return (Service)Storage.Find(match);
        }

        private List<Service> GetAllServices()
        {
            return Storage.Enumerate<Service>().ToList();
        }


        /// <summary>
        /// Get services due to its type(rated/unrated/all)
        /// </summary>
        /// <param name="ServiceType">Rated, Unrated, All by default</param>
        /// <returns>List of services</returns>
        public List<Service> GetAllServices(ServiceType seviceType)
        {
            List<Service> ret = new List<Service>();
            List<Service> AllServices = GetAllServices();

            switch (seviceType)
            {
                case ServiceType.Rated:

                    var RatedCollection = from item in AllServices where item.Rated select item;
                    ret = RatedCollection.ToList();
                    break;
                case ServiceType.Unrated:
                    var UnratedCollection = from item in AllServices where !(item.Rated) select item;
                    ret = UnratedCollection.ToList();
                    break;
                case ServiceType.All:
                    ret = AllServices;
                    break;
                default: break;
            }

            return ret;
        }

        /// <summary>
        /// Create new service
        /// </summary>
        /// <param name="ServiceName">Service Name</param>
        /// <param name="ServiceCost">Cost of Service</param>
        /// <param name="OrderID">ID of order for this service</param>
        public void CreateService(string ServiceName, double ServiceCost, int OrderID, bool RatedService = false)
        {
            Service _service = new Service { Name = ServiceName, Cost = ServiceCost, Rated = RatedService, ID = GetNewServiceNumber(), OrderID = OrderID };
            Storage.Add(_service);
            Storage.SaveChanges();
        }

        /// <summary>
        /// Get number for new service
        /// </summary>
        /// <returns>New ordinal number</returns>
        public int GetNewServiceNumber()
        {
            int result = 0;
            foreach (var item in GetAllServices())
            {
                if (item.ID >= result)
                {
                    result = item.ID + 1;
                }
            }
            return result;
        }

        /// <summary>
        /// Disposing
        /// </summary>
        /// <param name="disposeManaged"></param>
        protected override void Dispose(bool disposeManaged)
        {
            Storage = null;
        }

        /// <summary>
        /// Initializing repository
        /// </summary>
        private void initializeRepository()
        {
            Storage = new HotelResourcesRepository();
        }
    }
}
